package cn.neo.support.smartadapters.adapters;

import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;

import java.util.ArrayList;
import java.util.List;

import cn.neo.support.smartadapters.builders.BindableLayoutBuilder;
import cn.neo.support.smartadapters.builders.DefaultBindableLayoutBuilder;
import cn.neo.support.smartadapters.utils.Mapper;
import cn.neo.support.smartadapters.utils.ThreadHelper;
import cn.neo.support.smartadapters.utils.ViewEventListener;
import cn.neo.support.smartadapters.views.BindableLayout;
import cn.neo.support.smartadapters.views.BindableViewHolder;


/**
 * Adapter for {@code RecyclerView} based widgets
 */
public class RecyclerMultiAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements BasicSmartAdapter {

    protected Mapper mapper;
    protected List<Class> itemClassArray;
    protected List listItems;
    protected ViewEventListener viewEventListener;
    protected BindableLayoutBuilder builder;
    private boolean autoDataSetChanged = true;

    public RecyclerMultiAdapter(Mapper mapper, List listItems) {
        this(mapper, listItems, createDefaultBuilder());
    }

    public RecyclerMultiAdapter(Mapper mapper, List listItems, BindableLayoutBuilder builder) {
        this.listItems = listItems;
        this.mapper = mapper;
        if (builder == null) {
            this.builder = createDefaultBuilder();
        } else {
            this.builder = builder;
        }
        this.itemClassArray = new ArrayList<>(mapper.objectClasses());
    }

    @Override
    public void setItems(List items) {
        ThreadHelper.crashIfBackgroundThread();
        listItems = items;
        if (autoDataSetChanged) {
            notifyDataSetChanged();
        }
    }

    @Override
    public void addItem(Object item) {
        ThreadHelper.crashIfBackgroundThread();
        listItems.add(item);
        if (autoDataSetChanged) {
            notifyItemInserted(listItems.size() - 1);
        }
    }

    @Override
    public void delItem(Object item) {
        ThreadHelper.crashIfBackgroundThread();
        int position = listItems.indexOf(item);
        listItems.remove(position);
        if (autoDataSetChanged) {
            notifyItemRemovedChanged(position);
        }
    }

    public void delItem(int position) {
        ThreadHelper.crashIfBackgroundThread();
        listItems.remove(position);
        if (autoDataSetChanged) {
            notifyItemRemovedChanged(position);
        }
    }

    /**
     * 删除一个区间的数据
     *
     * @param begin 开始
     * @param last  结束
     */
    public void delRange(int begin, int last) {
        ThreadHelper.crashIfBackgroundThread();
        listItems.subList(begin, last).clear();
        int itemCount = last - begin;
        if (autoDataSetChanged) {
            notifyItemRangeRemoved(begin, itemCount);
            notifyDataSetChanged();
        }
    }

    @Override
    public void addItems(List items) {
        ThreadHelper.crashIfBackgroundThread();
        int startPosition = listItems.size();
        listItems.addAll(items);
        if (autoDataSetChanged) {
            notifyItemRangeChanged(startPosition, items.size());
        }
    }

    @Override
    public void replaceItem(int position, Object item) {
        ThreadHelper.crashIfBackgroundThread();
        listItems.remove(position);
        listItems.add(position, item);
        if (autoDataSetChanged) {
            notifyItemChanged(position);
        }
    }

    //替换，更新ITEM(唯一特殊的ViewType)
    public void replaceItem(Class viewTypeClass, Object item) {
        int position = mapper.viewTypeFromViewClass(viewTypeClass);
        replaceItem(position, item);
    }

    @Override
    public void clearItems() {
        ThreadHelper.crashIfBackgroundThread();
        listItems.clear();
        if (autoDataSetChanged) {
            notifyDataSetChanged();
        }
    }

    public void clearItemsNotNotify() {
        ThreadHelper.crashIfBackgroundThread();
        listItems.clear();
    }

    private void notifyItemRemovedChanged(int position) {
        notifyItemRemoved(position);
        if (position != getItemCount()) { // 如果移除的是最后一个，忽略
            notifyItemRangeChanged(position, getItemCount() - position);
        }
    }

    @Override
    public ViewEventListener getViewEventListener() {
        return viewEventListener;
    }

    @Override
    public void setViewEventListener(ViewEventListener viewEventListener) {
        this.viewEventListener = viewEventListener;
    }

    @Override
    public void notifyAction(int actionId, Object object, int position, View view) {
        if (viewEventListener != null) {
            viewEventListener.onViewEvent(actionId, object, position, view);
        }
    }

    @Override
    public void setAutoDataSetChanged(boolean enabled) {
        this.autoDataSetChanged = enabled;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = builder.build(parent, viewType, null, mapper);
        return new BindableViewHolder((BindableLayout) view);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        BindableViewHolder bindableViewHolder = (BindableViewHolder) holder;
        bindableViewHolder.setViewEventListener(viewEventListener);
        Object item = listItems.get(position);
        if (item != null) {
            bindableViewHolder.bind(item, position);
        }
    }

    @Override
    public int getItemViewType(int position) {
        if (listItems == null) {
            return 0;
        }
        Object object = listItems.get(position);
        return mapper.viewTypeFromViewClass(builder.viewType(object, position, mapper));
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public int getItemCount() {
        return listItems == null ? 0 : listItems.size();
    }

    public List getDataSource() {
        return listItems;
    }

    private static BindableLayoutBuilder createDefaultBuilder() {
        return new DefaultBindableLayoutBuilder();
    }
}
